#include <arduinoFFT.h>
#include <FastLED.h>

#define SAMPLES 64        // Must be a power of 2
#define MIC_IN A0         // Use A0 for mic input
#define LED_PIN     4     // Data pin to LEDS  D2
#define NUM_LEDS    256    // 灯珠数
#define BRIGHTNESS  150    // LED 亮度 
#define LED_TYPE    WS2812B
#define COLOR_ORDER GRB 
#define xres 16            // Total number of  columns in the display
#define yres 16            // Total number of  rows in the display

double vReal[SAMPLES];
double vImag[SAMPLES];

//幅值算法*************************************************************
//从group取出特征角标取出初始幅值→加上shift偏移→乘gain倍率→除以gain2倍率
//暂时只用了freq_gain2
int freq_group[8] = {2, 5, 12, 20, 30, 38, 50, 75};
int freq_shift[8] = {-50, -10, -10, -10, -5, -5, -5, -5};
int freq_gain[8] = {1, 1, 1, 1, 2, 2, 4, 4};
int freq_gain2[xres] = {40, 42, 45, 47, 51, 55, 57, 59, 62, 65, 69, 71, 73, 76, 80, 82};
//算出来的长度值
unsigned char freq_block[xres] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

int Intensity[xres] = { }; // initialize Frequency Intensity to zero
int Displacement = 1;

CRGB leds[NUM_LEDS];            // Create LED Object
arduinoFFT FFT = arduinoFFT();  // Create FFT object

int color = 0; //颜色变化
int color_rate = 1;  //单次变换间隔倍数
int color_interval = 1;  //颜色变换间隔

void setup() {
  pinMode(MIC_IN, INPUT);
  Serial.begin(115200);         //Initialize Serial
  delay(3000);                  // power-up safety delay
  FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip ); //Initialize LED strips
  FastLED.setBrightness(BRIGHTNESS);
}

void loop() {
  for(int i = 0; i < 4; i++){
    Visualizer(); 
    delay(1);
    flow(i);
  }
//  color += color_interval*color_rate;             // Increment the Hue to get the Rainbow
//  if(color>255){
//    color = 0;
//  }
//  for(int i =0;i<12;i++){
//    leds[i] = CRGB::Red;
//  }
//  
//  FastLED.show();
  
}

void flow(int rate){
  if(rate == 3){
    for(int i = 0; i < xres; i++){
      if(freq_block[i]>0){
        freq_block[i] = freq_block[i]-1;
       }
    }
  }
}

void Visualizer(){
  //Collect Samples
  getSamples();
  
  //Update Display
  displayUpdate();
  
  FastLED.show();
}

void getSamples(){
  for(int i = 0; i < SAMPLES; i++){
    vReal[i] = analogRead(MIC_IN);
    Serial.println(vReal[i]);
    vImag[i] = 0;
  }

  //FFT
  FFT.Windowing(vReal, 1, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
  FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
  FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);

  //Update Intensity Array
  for(int i = 2; i < (xres*Displacement)+2; i+=Displacement){
    vReal[i] = constrain(vReal[i],freq_gain2[i-2] ,1800);            // set max value for input data
    vReal[i] = map(vReal[i], freq_gain2[i-2], 1800, 0, yres);        // map data to fit our display

    Intensity[(i/Displacement)-2] --;                      // Decrease displayed value
    if (vReal[i] > Intensity[(i/Displacement)-2])          // Match displayed value to measured value
      Intensity[(i/Displacement)-2] = vReal[i];
  }

}


void displayUpdate(){
  color = 0;
  int nums = 0;
  for(int i = 0; i < xres; i++){
    for(int j = 0; j < yres; j++){
      if(i%2>0){
        nums = j; 
      }else{
        nums = yres-1-j;
      }
      if(j <= Intensity[i]){           // Light everything within the intensity range
        if(j>freq_block[i]){
          //freq_block[j] = min(j+1,7); 
        }
        leds[(i*yres)+nums] = CHSV(color, 255, BRIGHTNESS);
      }
      else{                                                  // Everything outside the range goes dark
        if(j == freq_block[i]){
          leds[(i*yres)+nums] = CHSV(color, 0, BRIGHTNESS);//白色坠落点
        }else{
          leds[(i*yres)+nums] = CHSV(color, 255, 0);
        }
          
      }
    }
    color += 255/xres;             // Increment the Hue to get the Rainbow
    if(color>255){
      color = 0;
    }
  }
}
